/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package pagoda.util.xml;

import java.io.File;
import java.io.FileReader;
import java.io.InputStream;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import pagoda.util.StringUtil;
import pagoda.util.exceptions.PagodaException;

/**
 *
 * @author kevin
 */
public class BasicNodeWalker<T> implements NodeWalker<T> {

    private Map<String, NodeVisitor<T>> _handlers
            = new HashMap<String, NodeVisitor<T>>();

    private T _context;

    public BasicNodeWalker(){
        
    }

    public BasicNodeWalker(T ctx){
        _context = ctx;
    }

    public BasicNodeWalker<T> setContext(T ctx)
    {
        _context = ctx;
        return this;
    }

    public void walk(Node node)
    {
        NodeList elements = node.getChildNodes();

        for(int i=0; i<elements.getLength(); i++)
        {
            Node child = elements.item(i);
            if(child instanceof Element)
            {
                Element element = (Element)child;
                String localname = StringUtil.IfNullOrEmpty(
                        element.getLocalName(),
                        element.getTagName()
                        );

                if(_handlers.containsKey(localname))
                {
                    NodeVisitor<T> handler = _handlers.get(localname);
                    handler.visitNode(child, _context);
                }
            }
        }
    }

    public void walk(String xml, String filename)
    {
        try {

            InputSource source = new InputSource();
            source.setCharacterStream(new StringReader(xml));
            Document d = PositionalXMLReader.readXML(source, filename);
            walk(d);
            
        } catch (Throwable ex) {
            throw new PagodaException("Failed to parse xml input string", ex);
        }
    }

    public void walk(File file)
    {
        try {

            FileReader fr = new FileReader(file);
            StringBuilder sb = new StringBuilder();
            char[] buff = new char[102400];
            int read = 0;
            while((read = fr.read(buff, 0, buff.length)) > 0)
            {
                sb.append(buff, 0, read);
            }
            walk(sb.toString(), file.getAbsolutePath());

        } catch (Throwable ex) {
            throw new PagodaException(ex, "Failed to parse xml input file '%s'", file.getAbsolutePath());
        }
    }

    public NodeWalker<T> register(String name, NodeVisitor<T> visitor) {
        _handlers.put(name, visitor);
        return this;
    }
}
